/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** *****************************************************************************************************
 * \file     McuLp.c                                                                                    *
 * \brief    MCAL LP Driver                                                                             *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2025/3/4       <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif
/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "RegHelper.h"
#include "__regs_base.h"
#include "Mcal_Delay.h"
#include "irq.h"
#include "Mcu.h"
#include "McuLp.h"
#include "Mcu_Rstgen.h"
#include "debug.h"

/********************************************************************************************************
 *                                 Private Macro definition                                             *
 *******************************************************************************************************/

/********************************************************************************************************
 *                                  Private Constant Definitions                                        *
 *******************************************************************************************************/

#define MCULP_START_SEC_CONST_UNSPECIFIED
#include "McuLp_MemMap.h"


#define MCULP_STOP_SEC_CONST_UNSPECIFIED
#include "McuLp_MemMap.h"

/********************************************************************************************************
 *                                  Private Variable Definitions                                        *
 *******************************************************************************************************/

#define MCULP_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "McuLp_MemMap.h"

#define MCULP_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "McuLp_MemMap.h"

#define MCULP_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "McuLp_MemMap.h"

static McuLp_ModuleType mculp_dev;

static void (* McuLp_mbox_chan_state_ack_callback)(lp_state_t *);
static void (* McuLp_mbox_chan_custom_ack_callback)(void *);

static lp_comm_msg_t lp_req __attribute__((aligned(SDRV_MBOX_BUF_ALIGN_BYTES)));

#define MCULP_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "McuLp_MemMap.h"

/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
#define MCULP_START_SEC_CODE_FAST
#include "McuLp_MemMap.h"

#define MCULP_STOP_SEC_CODE_FAST
#include "McuLp_MemMap.h"

#define MCULP_START_SEC_CODE
#include "McuLp_MemMap.h"

/** \brief The offset address of the gpio core select register. */
#define GPIO_DGSELN_0      ((uint32_t)0x140U)
/** \brief The size of the gpio core select register. */
#define GPIO_DGSELN_SIZE   ((uint32_t)0x04U)
/** \brief The offset bit of the gpio core select. */
#define GPIO_RGN_DGSEL_BIT (1U)
#define GPIO_RGN_DGSEL_BIT_MASK (0xFU)
/** \brief The bit mask of enabling the gpio permission control. */
#define GPIO_RGN_EN        (1UL)
/** \brief The offset address of the gpio core select register for different pin channels. */
#define GPIO_DGSELN_ADDR(n) (GPIO_DGSELN_0 + ((n)*GPIO_DGSELN_SIZE))

/** *****************************************************************************************************
 * \brief McuLp GPIO Allocation.
 *
 * \verbatim
 * Syntax             : void McuLp_gpio_alloc2_core(uint32 pin_index, uint32 core);
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : None
 *
 * Reentrancy         : None
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : McuLp GPIO Allocation.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
void McuLp_gpio_alloc2_core(uint32 pin_index, uint32 core)
{
    uint32 temp_val;
    uint32 gpio_base = APB_GPIO_LP_BASE;

    /* Select and Enable the assignment of the gpio pin. */
    temp_val  = readl(gpio_base + GPIO_DGSELN_ADDR(pin_index));
    temp_val &= ~(GPIO_RGN_DGSEL_BIT_MASK);
    temp_val |= core << GPIO_RGN_DGSEL_BIT;
    temp_val |= GPIO_RGN_EN;
    writel(temp_val, gpio_base + GPIO_DGSELN_ADDR(pin_index));
}

/** *****************************************************************************************************
 * \brief McuLp Mailbox Channel rxcallback
 *
 * \verbatim
 * Syntax             : static int32_t McuLp_mbox_chan_rxcallback(void *arg,uint16_t proc_id,
 *                                                                uint8_t *msg, uint32_t len)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : None
 *
 * Reentrancy         : None
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : McuLp Mailbox Channel rxcallback.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static int32_t McuLp_mbox_chan_rxcallback(void *arg,uint16_t proc_id, uint8_t *msg, uint32_t len)
{
    void *ptr = NULL_PTR;
    lp_comm_msg_t *lp_comm = NULL_PTR;

    if (len == sizeof(lp_comm_msg_t) && msg) {

        lp_comm = (lp_comm_msg_t *)(uint32)msg;
        ptr = &(lp_comm->reserved[0]);

        switch (lp_comm->cmd)
        {
        case LP_CMD_STATE_ACK:
            if (McuLp_mbox_chan_state_ack_callback != NULL_PTR) {
                McuLp_mbox_chan_state_ack_callback((lp_state_t *)ptr);
            }
            break;
        case LP_CMD_CUSTOM_ACK:
            if (McuLp_mbox_chan_custom_ack_callback != NULL_PTR) {
                McuLp_mbox_chan_custom_ack_callback(ptr);
            }
            break;
        default:
            break;
        }
    }

    return 0;
}

/** *****************************************************************************************************
 * \brief This function is used to initialize the mculp.
 *
 * \verbatim
 * Syntax             : Std_ReturnType McuLp_Init(sdrv_mbox_t *dev)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This function is used to initialize the mculp.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
Std_ReturnType McuLp_Init(sdrv_mbox_t *dev)
{
    Std_ReturnType ret = E_OK;
    sdrv_mbox_chan_req_t chan_req;
    uint32 v;

    if (NULL_PTR == mculp_dev.mbox_chan) {
        if (dev) {
            /* channel config */
            chan_req.rproc = MBOX_RPROC_CR5LP;
            chan_req.channel_id = MBOX_CHN_ID_PM;

            /* request channel */
            mculp_dev.mbox_chan = sdrv_mbox_request_channel(dev, &chan_req);
            if (NULL_PTR != mculp_dev.mbox_chan) {
                mculp_dev.mbox_dev = dev;
                /* set receive callback */
                sdrv_mbox_set_callback(mculp_dev.mbox_chan, McuLp_mbox_chan_rxcallback, mculp_dev.mbox_chan);
                /* Set CR52 Lowpower Mbox Ready BIT */
                v = Mcu_Ip_RstgenLldReadGeneralReg(APB_RSTGEN_LP_BASE, RESET_GENERAL_REG_SF_BOOT_ID);
                v |= (0x1U << RESET_GENERAL_REG_SF_BOOT_CR52_LP_MB_READY);
                Mcu_Ip_RstgenLldWriteGeneralReg(APB_RSTGEN_LP_BASE, RESET_GENERAL_REG_SF_BOOT_ID, v);
            } else {
                ret = MCULP_E_MBOX_ERR;
            }
        } else {
            ret = MCULP_E_PARAMS;
        }
    } else {
        /* Already initialized */
        ret = E_OK;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This service activates the MCU power modes.
 *
 * \verbatim
 * Syntax             : static Std_ReturnType McuLp_SetMode(lp_cmd_type cmd)
 *
 * Service ID[hex]    : None
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This service activates the MCU power modes(Sleep mode)
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
static Std_ReturnType McuLp_SetMode(lp_cmd_type cmd)
{
    Std_ReturnType ret = E_OK;

    if (NULL_PTR != mculp_dev.mbox_chan) {

        /* Wait CR5LP Lowpower Mbox Ready BIT */
        if (Mcu_Ip_RstgenLldReadGeneralReg(APB_RSTGEN_LP_BASE, RESET_GENERAL_REG_SF_BOOT_ID) &
           (0x1U << RESET_GENERAL_REG_SF_BOOT_CR5LP_LP_MB_READY)) {

            DBG("\nCR5LP Mbox ready.\r\n");
            lp_req.cmd = cmd;

            ret = sdrv_mbox_send(mculp_dev.mbox_chan, (uint8_t *)(&lp_req),
                                    sizeof(lp_req), 1000U);
            if (ret != 0) {
                ret = MCULP_E_MBOX_ERR;
            }
        } else {
            DBG("\nCR5LP Mbox not ready.\r\n");
            ret = MCULP_E_CR5LP_MBOX_NO_INIT;
        }
    } else {
        ret = MCULP_E_MBOX_NO_INIT;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This service activates the MCU power modes.
 *
 * \verbatim
 * Syntax             : void Mcu_SetMode(Mcu_ModeType McuMode)
 *
 * Service ID[hex]    : 0x08
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : None
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : This service activates the MCU power modes.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
void Mcu_SetMode(Mcu_ModeType McuMode)
{
    if (MCU_MODE_SLEEP == McuMode) {
        McuLp_SetMode(LP_CMD_ENTER_SLEEP);
    } else if (MCU_MODE_HIB == McuMode) {
        McuLp_SetMode(LP_CMD_ENTER_HIB);
    } else if (MCU_MODE_RTC == McuMode) {
        McuLp_SetMode(LP_CMD_ENTER_RTC);
    } else if (MCU_MODE_LPRUN == McuMode) {
        McuLp_SetMode(LP_CMD_ENTER_LPRUN);
    } /* else not needed */
}

/** *****************************************************************************************************
 * \brief This function is used to obtain LP state information.
 *
 * \verbatim
 * Syntax             : Std_ReturnType McuLp_LpStateGet(void (*callback)(lp_state_t *))
 *
 * Service ID[hex]    : 0x08
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : callback: callback for get lp state
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Get RTC Mode wake-up source, powerdown reason and other information from CR5LP.
 *                      CR5LP returns information via callback.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
Std_ReturnType McuLp_LpStateGet(void (*callback)(lp_state_t *))
{
    Std_ReturnType ret = E_OK;

    if (NULL_PTR != mculp_dev.mbox_chan) {

        /* Wait CR5LP Lowpower Mbox Ready BIT */
        if (Mcu_Ip_RstgenLldReadGeneralReg(APB_RSTGEN_LP_BASE, RESET_GENERAL_REG_SF_BOOT_ID) &
           (0x1U << RESET_GENERAL_REG_SF_BOOT_CR5LP_LP_MB_READY)) {

            McuLp_mbox_chan_state_ack_callback = callback;

            DBG("\nCR5LP Mbox ready.\r\n");
            lp_req.cmd = LP_CMD_STATE_GET;

            ret = sdrv_mbox_send(mculp_dev.mbox_chan, (uint8_t *)(&lp_req),
                                    sizeof(lp_req), 1000U);
            if (ret != 0) {
                ret = MCULP_E_MBOX_ERR;
            }
        } else {
            DBG("\nCR5LP Mbox not ready.\r\n");
            ret = MCULP_E_CR5LP_MBOX_NO_INIT;
        }
    } else {
        ret = MCULP_E_MBOX_NO_INIT;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief This function is used to obtain LP custom data.
 *
 * \verbatim
 * Syntax             : Std_ReturnType McuLp_LpStateGet(void (*callback)(lp_state_t *))
 *
 * Service ID[hex]    : 0x08
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : callback: callback for get lp state
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Get user-defined data from CR5LP. If users have the need to obtain
 *                      data from CR5LP, they can achieve it through this interface.
 *                      The maximum data length is 60B. CR5LP returns information via callback.
 * \endverbatim
 * Traceability       : None
 *******************************************************************************************************/
Std_ReturnType McuLp_LpCustomGet(void (*callback)(void *))
{
    Std_ReturnType ret = E_OK;

    if (NULL_PTR != mculp_dev.mbox_chan) {

        /* Wait CR5LP Lowpower Mbox Ready BIT */
        if (Mcu_Ip_RstgenLldReadGeneralReg(APB_RSTGEN_LP_BASE, RESET_GENERAL_REG_SF_BOOT_ID) &
           (0x1U << RESET_GENERAL_REG_SF_BOOT_CR5LP_LP_MB_READY)) {

            McuLp_mbox_chan_custom_ack_callback = callback;

            DBG("\nCR5LP Mbox ready.\r\n");
            lp_req.cmd = LP_CMD_CUSTOM_GET;

            ret = sdrv_mbox_send(mculp_dev.mbox_chan, (uint8_t *)(&lp_req),
                                    sizeof(lp_req), 1000U);
            if (ret != 0) {
                ret = MCULP_E_MBOX_ERR;
            }
        } else {
            DBG("\nCR5LP Mbox not ready.\r\n");
            ret = MCULP_E_CR5LP_MBOX_NO_INIT;
        }
    } else {
        ret = MCULP_E_MBOX_NO_INIT;
    }

    return ret;
}

#define MCULP_STOP_SEC_CODE
#include "McuLp_MemMap.h"

#ifdef __cplusplus
}
#endif
/* End of file */
